import { Request, Response, NextFunction } from 'express';
import { v4 as uuidv4 } from 'uuid';
import logger from '@utils/logger';

declare global {
  namespace Express {
    interface Request {
      id?: string;
      startTime?: number;
    }
  }
}

/**
 * Request ID middleware
 * Generates or extracts a unique request ID for tracing
 */
export function requestIdMiddleware(req: Request, res: Response, next: NextFunction): void {
  // Check if request ID is provided in headers (for distributed tracing)
  const requestId = req.headers['x-request-id'] as string ||
                    req.headers['x-correlation-id'] as string ||
                    uuidv4();

  // Attach request ID to request object
  req.id = requestId;

  // Attach start time for performance tracking
  req.startTime = Date.now();

  // Set response header with request ID
  res.setHeader('X-Request-ID', requestId);

  // Create a child logger with request context
  const requestLogger = logger.child({
    requestId,
    method: req.method,
    path: req.path,
    ip: req.ip || req.socket.remoteAddress,
  });

  // Override req properties to use request logger
  (req as any).logger = requestLogger;

  next();
}

/**
 * Request logging middleware
 * Logs incoming requests and their responses
 */
export function requestLoggingMiddleware(req: Request, res: Response, next: NextFunction): void {
  const requestLogger = (req as any).logger || logger;

  // Log incoming request
  requestLogger.info('Incoming request', {
    method: req.method,
    url: req.originalUrl,
    query: req.query,
    userAgent: req.get('User-Agent'),
    userId: (req as any).user?.userId,
  });

  // Capture response
  const originalSend = res.send;
  res.send = function (data: any): Response {
    // Calculate request duration
    const duration = req.startTime ? Date.now() - req.startTime : 0;

    // Log response
    requestLogger.info('Outgoing response', {
      method: req.method,
      url: req.originalUrl,
      statusCode: res.statusCode,
      duration,
      userId: (req as any).user?.userId,
    });

    // Log performance warning for slow requests
    if (duration > 1000) {
      requestLogger.warn('Slow request detected', {
        method: req.method,
        url: req.originalUrl,
        duration,
        threshold: 1000,
      });
    }

    return originalSend.call(this, data);
  };

  next();
}

/**
 * Error logging middleware
 * Logs errors with request context
 */
export function errorLoggingMiddleware(error: Error, req: Request, res: Response, next: NextFunction): void {
  const requestLogger = (req as any).logger || logger;

  requestLogger.error('Request error', error, {
    requestId: req.id,
    method: req.method,
    url: req.originalUrl,
    statusCode: res.statusCode,
    userId: (req as any).user?.userId,
  });

  next(error);
}
